#ifndef LUNA_LIB_H
#define LUNA_LIB_H 1

//	http://www.lua.org/notes/ltn005.html

/*-----------------------------------------------------------------------------
 * First :
    class Foo {
	public:
		Foo(lua_State *L)		{	printf("in Constructor\n");	}
		int foo(lua_State *L)	{	printf("in foo\n");			}
		~Foo()					{	printf("in destructor\n");	}

		static udptr_s	root;
		static const char classname[];
		static const Luna<Foo>::RegType_s func_register[];
    };

	Luna<Foo>::udptr_s	root;
    const char Foo::classname[] = "Foo";
    const Luna<Foo>::RegType_s Foo::func_register[] = {
		{ "foo", &Foo::foo },
		{ 0 }
    };

 * Then :
    Luna<Foo>::Register(L);
    
 * From Lua :
    local foo = Foo()
    foo:foo()

 * Result :
    in Constructor
    in foo
    in destructor
-----------------------------------------------------------------------------*/

#define LUNALIB_DECLARE(cls)			\
	static const char classname[];		\
	static const LunaLib<cls>::RegType_s func_register[];


#define LUNALIB_IMP_BEGIN(cls)					\
	const char cls::classname[] = #cls;			\
	typedef cls __luna_lib__;					\
	cls *LunaLib<cls>::luna_self_ptr = NULL;	\
	const LunaLib<cls>::RegType_s cls::func_register[] = {
	
#define LUNALIB_IMP_METHOD(cls, method)	{ #method, &cls::method },
#define LUNALIB_IMP_END()				{ 0 } };

/*-----------------------------------------------------------------------------
	Luna itself :
-----------------------------------------------------------------------------*/

template<typename T> class LunaLib {

		public: struct RegType_s {
			const char *name;
			int(T::*mfunc)(lua_State*);
		};
		
		protected: static T *luna_self_ptr;

		/*---------------------------------------------------------------------
		*	Register() - registers object stuff 
		---------------------------------------------------------------------*/
		public: LunaLib (const char *libname, lua_State *L) {

			if (luna_self_ptr) {
				RAISE_RUNTIME_ERROR(va("LunaLib '%s' is already initialized", libname));
			}
			
			//	create or use existing metatable (now it is on top) :
			luna_self_ptr	=	(T*)this;

			lua_newtable(L);
			
			//	register methods :
			for (int i = 0; T::func_register[i].name; i++) {
				lua_pushnumber(L, i);
				lua_pushcclosure(L, &LunaLib<T>::CallProxy, 1);
				lua_setfield(L, -2, T::func_register[i].name);
			}

			lua_setglobal(L, libname);
		}
		
		public: ~LunaLib ( void ) {	
			luna_self_ptr	=	NULL;
		}
		
		/*---------------------------------------------------------------------
		*	CallProxy()
		---------------------------------------------------------------------*/
		private: static int CallProxy(lua_State *L) {
			int i = (int)lua_tonumber(L, lua_upvalueindex(1)); // which function?
			return (luna_self_ptr->*(T::func_register[i].mfunc))(L); // execute method
		}
	};


#endif /* LUNA_LIB_H */

